<?php
class DbModule extends Module{
	
	public $name = 'db';
	public $dependencies = array('builder');
	private $connections = array();
	private $active_connection;
	private $tables;
	private $profiler;
	
	public function DbModule(&$application){
		$this->Module($application);
		$this->profiler = new Profiler();
		$this->builder->db = &$this;
		$this->connect();
	}
	
	public function connect($host=DB_HOST, $user=DB_USER, $pass=DB_PASS, $db=DB_NAME){
		$this->connections[$db] = @mysql_connect(DB_HOST, DB_USER, DB_PASS) or $this->app->err->fatal_error('Cannot connect to database.');
		$this->set_connection($db);
	}
	
	public function set_connection($conn){
		$this->active_connection = $conn;
		if(!mysql_select_db($conn, $this->connections[$conn])){
			$this->app->err->fatal_error('Database <strong>'.DB_NAME.'</strong> does not exist.');
		}
		$this->map_tables();
	}
	
	public function query($query=null){
		if(!$query){$this->app->err->dump_error("No query string provided.");return false;}
		$this->profiler->start();
		$result = mysql_query($query);
		$running_time = $this->profiler->end();
		$this->app->err->debug($query, 'MySQL query ('.$running_time.')');
		if($err = mysql_error()){
			$this->app->err->dump_error('MySQL error: <b>'.$err.'</b>');
		}
		return $result;
	}
	
	public function get_records($result=null){
		if(!$result){$this->app->err->dump_error("No resultset provided for fetching data.");return false;}
		if(mysql_num_rows($result) > 0){
			$records = array();
			while($row = mysql_fetch_assoc($result)){
				$records[] = $row;
			}
			mysql_free_result($result);
			return $records;
		}else{
			return false;
		}
	}
	
	public function get_rows_q($query){
		$rows = $this->get_records($this->query($query));
		return $rows;
	}
	
	private function map_tables(){
		$_tables = $this->get_rows_q("SHOW TABLES");
		if($_tables){
			foreach($_tables as $_table){
				$_table = shift($_table);
				if(!DB_PREFIX || strpos(DB_PREFIX, $_table)!==false){
					$this->tables[str_replace(DB_PREFIX, '', $_table)] = $_table;
				}
			}
		}
	}
	
	public function check_table($table=null, $verbose=true){
		if($this->tables){
			if(!$table){
				if($verbose) $this->app->err->dump_warning('No table specified.');
				return false;
			}elseif(!in_array($table, array_keys($this->tables))){
				if($verbose) $this->app->err->dump_warning('Table '.$table.' does not exist.');
				return false;
			}else{
				return true;
			}
		}else{
			return false;
		}
	}
	
	public function get_rows($table, $conditions=null, $fields=null, $order=null, $limit=null){
		if(!$this->check_table($table)){
			return false;
		}
		$table = $this->tables[$table];
		if(!$fields){
			$fields = '*';
		}
		$this->builder->reset();
		$this->builder->select($fields, $table);
		if($conditions){
			$this->builder->where($conditions, $table);
		}
		if($order){
			list($ord_field, $ord_dir) = explode(' ',$order);
			if(!$ord_dir){
				$ord_dir = 'ASC';
			}
			$this->builder->order($ord_field, $table, $ord_dir);
		}
		if($limit){
			$this->builder->limit($limit);
		}
		return $this->get_rows_q($this->builder->get());
	}
	
	public function get_row($table, $conditions=null, $fields=null){
		if(is_numeric($conditions)){
			$conditions = array('id'=>$conditions);
		}
		return shift($this->get_rows($table, $conditions, $fields, null, '0,1'));
	}
	
	public function get_field($table, $field=null, $conditions=null){
		if($row = $this->get_row($table, $conditions, array($field))){
			$val = shift($row);
			return $val;
		}else{
			return false;
		}
	}
	
	public function insert_row($table, $data){
		if(!$this->check_table($table)){
			return false;
		}
		$table = $this->tables[$table];
		if(!$data){
			$this->app->err->dump_warning('Cannot insert empty row.');
			return false;
		}
		$fields = implode(', ', $this->builder->quote(array_keys($data)));
		$values = implode(', ', array_values(quote($data)));
		$model = 'INSERT INTO `%s`(%s) VALUES(%s)';
		
		if($this->query(sprintf($model, $table, $fields, $values))){
			$id = mysql_insert_id();
			return $id;
		}else{
			return false;
		}
	}
	
	public function insert_rows($table, $data){
		if(!$this->check_table($table)){
			return false;
		}
		if(!$data || !is_array($data[0])){
			$this->app->err->dump_warning('Invalid data provided for insert_rows.');
			return false;
		}
		foreach($data as $row){
			$this->insert_row($table, $row);
		}
	}
	
	public function update_row($table, $data=null, $id=null){
		if(!$this->check_table($table)){
			return false;
		}
		$table = $this->tables[$table];
		if(!$data){
			$this->app->err->dump_warning('Update data empty. Cannot update row.');
			return false;
		}
		if(!$id){
			$this->app->err->dump_warning('You must specify an id or conditions for the updated row.');
			return false;
		}
		
		$update = array();
		foreach($data as $field => $value){
			$update[] = $this->builder->quote($field).'='.quote($value);
		}
		
		$conditions = is_numeric($id) ? array('id'=>$id) : $id;
		$condition = array();
		foreach($conditions as $field => $value){
			$condition[] = $this->builder->quote($field).'='.quote($value);
		}
		
		$model = 'UPDATE `%s` SET %s WHERE %s';
		$query = sprintf($model, $table, implode(', ',$update), implode(' AND ',$condition));
		return $this->query($query);
	}
	
	public function save_row($table, $data=null, $id=null){
		if(!$this->check_table($table)){
			return false;
		}
		if(!$data){
			$this->app->err->dump_warning('Save data empty. Cannot save row.');
			return false;
		}
		if($id){//update
			return $this->update_row($table, $data, $id);
		}else{
			return $this->insert_row($table, $data);
		}
	}
	
	public function delete_row($table, $id){
		if(!$this->check_table($table)){
			return false;
		}
		
		$conditions = is_numeric($id) ? array('id'=>$id) : $id;
		$condition = array();
		foreach($conditions as $field => $value){
			$condition[] = $this->builder->quote($field).'='.quote($value);
		}
		
		$model = 'DELETE FROM `%s` WHERE %s LIMIT 1';
		$query = sprintf($model, $table, implode(' AND ',$condition));
		return $this->query($query);
	}
	
	public function delete_rows($table, $conditions){
		if(!$this->check_table($table)){
			return false;
		}
		
		$condition = array();
		foreach($conditions as $field => $value){
			$condition[] = $this->builder->quote($field).'='.quote($value);
		}
		
		$model = 'DELETE FROM `%s` WHERE %s';
		$query = sprintf($model, $table, implode(' AND ',$condition));
		return $this->query($query);
	}
}
?>